import { isArray, isFunction, isObject, isUndefined } from "../shared";

/**
 * 创建一个 value 的浅拷贝。
 * @param value - 要拷贝的值
 * @returns 返回拷贝后的值。
 * @example
 * const objects = [{ 'a': 1 }, { 'b': 2 }];
 * const shallow = clone(objects);
 * shallow[0] === objects[0]
 * // => true
 */
export function clone(value: any) {
    if(isArray(value)) {
        return [...value]
    }

    if(isObject(value)) {
        return {...value}
    }

    return value
}

/**
 * 这个方法类似 clone，除了它会递归拷贝 value。（注：也叫深拷贝）。
 * @param value - 要深拷贝的值。
 * @return 返回拷贝后的值。
 * @example
 * const objects = [{ 'a': 1 }, { 'b': 2 }];
 * const deep = cloneDeep(objects);
 * deep[0] === objects[0]
 * // => false
 */
export function cloneDeep(value: any) {

    if (!isObject(value)) return value;

    if (isArray(value)) {
        return value.map(item => cloneDeep(item))
    }

    if (isObject(value)) {
        const result = {};
        for (const key in value) {
            if (value.hasOwnProperty(key)) {
                result[key] = cloneDeep(value[key]);
            }
        }
        return result;
    }

    return value;
}

/**
 * 这个方法类似 clone，除此之外它还接收一个 customizer 回调函数，定制返回的克隆值。 
 * 如果 customizer 返回 undefined 将会使用拷贝方法代替处理。
 * @param value - 用来递归克隆的值。
 * @param customizer - 自定义克隆的函数。
 * @returns 返回克隆值。
 * @example
 * const object = { a: 1, b: 2 };
 * const cloned = cloneWith(object, (value) => {
 *   if (value === 1) {
 *       return 100;
 *   }
 * });
 * // => { a: 100, b: 2 };
 */
export function cloneWith(value: any, customizer: Function) {
    if (!isObject(value)) return value;

    if(!customizer || !isFunction(customizer)) return clone(value)

    if(isArray(value)) {
        return value.map(val => {
            const customizerRes = customizer(val);
            return isUndefined(customizerRes) 
                ? val
                : customizerRes;
        })
    }

    if(isObject(value)) {
        const result = {};
        for (const key in value) {
            const val = value[key]
            const customizerRes = customizer(val);

            result[key] = isUndefined(customizerRes) 
                ? val
                : customizerRes; 
        }
        return result;
    }
    
    return value
}

/**
 * 这个方法类似 cloneWith，除了它会递归克隆 value。
 * @param value - 用来递归克隆的值。
 * @param customizer - 自定义克隆的函数。
 * @returns 返回克隆值。
 * @example
 * const object = { a: { c: 1 }, b: 2 };
 * const cloned = cloneWith(object, (value) => {
 *   if (value === 1) {
 *       return 100;
 *   }
 * });
 * // => { a: { c: 100 }, b: 2 }
 */
export function cloneDeepWith(value: any, customizer?: Function) {
    if (!isObject(value)) return value;

    if(!customizer || !isFunction(customizer)) return cloneDeep(value)

    if(isArray(value)) {
        return value.map(val => {
            const customizerRes = customizer(val);
            return isUndefined(customizerRes) 
                ? cloneDeepWith(val, customizer) 
                : customizerRes;
        })
    }

    if(isObject(value)) {
        const result = {};
        for (const key in value) {
            const val = value[key]
            const customizerRes = customizer(val);

            result[key] = isUndefined(customizerRes) 
                ? cloneDeepWith(val, customizer) 
                : customizerRes; 
        }
        return result;
    }
    
    return value
}